package com.lkx.apsect;


import com.lkx.annotation.CloudLimitAnnottion;
import com.lkx.dto.InterfaceVisitorRecordDTO;
import com.lkx.dto.RequestLimitDTO;
import com.lkx.exception.CloudLimitException;
import com.lkx.service.strategy.CloudLimitService;
import com.lkx.util.HttpUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

@Slf4j
@Aspect
@Component
public class CloudLimitApsect {

    @Autowired
    private CloudLimitService limitService;


    @Autowired
    RestTemplate restTemplate;
    @Value("${cloud.limit.record-limit-url:}")
    private String recordLimitUrl;


    @Pointcut("@annotation(com.lkx.annotation.CloudLimitAnnottion)")
    public void requestLimit(){

    }

    @Before("requestLimit()")
    public void doBefore(JoinPoint joinPoint){
        //log.info("-----------limit begin----------");
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        CloudLimitAnnottion cloudLimitAnnottion = method.getAnnotation(CloudLimitAnnottion.class);
        //log.info("限流类型：[{}]",cloudLimitAnnottion.type().getDesc());


        InterfaceVisitorRecordDTO paramsDto = new InterfaceVisitorRecordDTO();
        paramsDto.setInterfaceName(cloudLimitAnnottion.annotationType().getTypeName());
        paramsDto.setVisitorTime(LocalDateTime.now());
        paramsDto.setStatus(0);


        RequestLimitDTO dto = new RequestLimitDTO();
        dto.setLimiter(cloudLimitAnnottion);
        dto.setKey(signature.getName());

        //限流检测
        if(limitService.checkRequestLimit(dto)){
            //log.error("【"+cloudLimitAnnottion.type().getDesc()+"】触发限流上限"+cloudLimitAnnottion.limitCount());
            paramsDto.setStatus(1);
            //监控服务地址配置了，该方法才生效-暂时对外版本不提供该功能
            //recordLimit(recordLimitUrl,paramsDto);
            //throw new CloudLimitException("【"+cloudLimitAnnottion.type().getDesc()+"】触发限流上限值="+cloudLimitAnnottion.limitCount());
            throw new CloudLimitException(dto.getLimiter().limitMsg());
        }

    }

    private void recordLimit(String recordLimitUrl,InterfaceVisitorRecordDTO paramsDto){
        //如果配置了记录限流，则会调用服务端记录请求，需要先部署监控服务
        if(null != recordLimitUrl && StringUtils.hasText(recordLimitUrl)){
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = requestAttributes.getRequest();
            String url = request.getRequestURL().toString();
            String ip  = request.getRemoteAddr();

            paramsDto.setInterfaceUrl(url);
            paramsDto.setVisitorIp(ip);

            HttpUtils.postForJson(restTemplate,recordLimitUrl,paramsDto);
        }
    }



}

